package warbots.gameplay;

import java.awt.Point;
import java.util.HashSet;
import java.util.Set;

import warbots.entities.units.Unit;
import warbots.gameplay.exceptions.GameplayException;

/**
 * @author Ido Adler.
 */
public class Map
{
    private int sum;
    public Cell[][] _board = new Cell[3][3];
    public Set<Cell> _starting = new HashSet<Cell>();
    
    /**
     * TODO: description
     * 
     * @throws GameplayException
     */
    public Map() {
        
        for (int i = 0; i < _board.length; i++)
            for (int j = 0; j < _board[i].length; j++)
                _board[i][j] = new Cell();
        
        _board[1][1].setBlocked(true);
        
        _starting.add(_board[0][0]);
        _starting.add(_board[2][2]);
        
        setSum(2);
    }
    
    /**
     * TODO: description
     * 
     */
    public void init()
    {
       
    }
    
    
    private void setSum(final int sum)
    {
        this.sum = sum;
    }
    
    public int getSum()
    {
        return sum;
    }

	/**
	 * Maps can choose the next unit to play, only when the map
	 * allows the players to choose units, he can choose it himself
	 * @param units
	 * @return
	 */
    public Unit chooseUnit(Set<Unit> units) {
		// this implementation does not choose the unit, and the played will choose it 
    	return null;
	}
    
    /**
     * Distance between 2 cells.
     * 
     */
    public int distance(Cell a, Cell b){
    	Point p1 = find(a);
    	Point p2 = find(b);
    	
    	if (p1 == null || p2 == null)
    		return -1;
    	
    	return (int)Math.floor(p1.distance(p2));
    }
    
    /**
     * Returns a set of cells within the given radius r
     * @param r - the radius of the cells to find
     * @return Set of cells, within hit range of damage
     */
    public Set<Cell> cellsInRadius(Cell c, int r){
    	Set<Cell> range = new HashSet<Cell>();
    	Point p = find(c);
    	
    	// find all points in range r
    	Set<Point> pointsInRange = pointsInRange(p, r);

    	for (Point point : pointsInRange) {
			// if point is legal, add the cell to the set
    		if (isInside(point))
    			range.add(_board[point.x][point.y]);
		}
    	
    	return range;
    }
    
    /**
     * Finds all points in range r, from the given point p
     * @param p
     * @return
     */
    protected Set<Point> pointsInRange(Point p, int r){
    	Set<Point> points = new HashSet<Point>();
    	
    	for(int i = 0; i < r; i ++)
    		for(int j = 0; j < r; j++){
    			testAndSetPoint(p, new Point(p.x + i, p.x + j), points, r); // i
    			testAndSetPoint(p, new Point(p.x - i, p.x + j), points, r); // ii
    			testAndSetPoint(p, new Point(p.x - i, p.x - j), points, r); // iii
    			testAndSetPoint(p, new Point(p.x + i, p.x - j), points, r); // iv
    		}
    	
    	return points;
    }

    private Set<Point> testAndSetPoint(Point base, Point p, Set<Point> set, int r){
    	if (base.distance(p) <= r)
    		set.add(p);
    	
    	return set;
    }
    
    /**
     * Find the point (position) of the given cell
     * @return Point representing the index of the given cell.
     * if the cell is not in the map, returns null 
     */
    public Point find(Cell a){
    	for (int i = 0; i < _board.length; i++)
    		for (int j = 0; j < _board[i].length; j++){
    			if (a == _board[i][j])
    				return new Point(i,j);
    		}
    	return null;
    }
    
    public boolean isInside(Point p){
    	return ((p.x >= 0 && p.x < _board.length) &&
    		(_board.length > 0 && p.y >= 0 && p.y < _board[0].length));
    }

	public void initRound() {
		// do whatever there is to do before each round begins
		// whether it is to rebuild the damage, grow the flowers 
		// or remove the old and unusable artifacts
	}

	public Point chooseCell() {
		// let player choose target for actions
		String x = GamePlay.read("choose X for target [1.."+_board.length+"]: ");
		String y = GamePlay.read("choose Y for target [1.."+_board[0].length+"]: ");
		return new Point(Integer.parseInt(x)-1,Integer.parseInt(y)-1);		
	}

	public void place(Unit unit) throws GameplayException {
		for (Cell cell:_starting)
		{
			if (!cell.isBlocked() && cell.getUnit()==null)
			{
				cell.setUnit(unit);
				unit.setPosition(find(cell));
				// TODO: set direction
				return;
			}
		}
		throw new GameplayException("no place for unit "+ unit.getName());
	}
    
}
